﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.ServiceModel;
using System.Configuration;
using System.Diagnostics;

namespace DigDes.DS2012.ProcessingService.Client
{
    static class WCFClient
    {
        private static TraceSource clientTrace = new TraceSource("WCFClient");
        static int _traceID = 0;
        static byte _numberOfReconnection, _reconnectsLeft;
        static ServiceReference1.ProcessingServiceClient _client;

        static WCFClient()
        {
            InitTrace();
                          
            bool parsed= 
                Byte.TryParse(ConfigurationManager.AppSettings["NumberOfReconnection"], out _numberOfReconnection);
            if (!parsed)
            {
                _numberOfReconnection = 0;
            }

            _reconnectsLeft = _numberOfReconnection;
            _client = new ServiceReference1.ProcessingServiceClient();
            OpenProxy();
        }
     
       
        static private void InitTrace()
        {
            clientTrace.Switch = new SourceSwitch("clientTraceSwitch", "All");
            clientTrace.Listeners.Clear();
            //ConsoleTraceListener consoleListner = new ConsoleTraceListener();
            TextWriterTraceListener errorListner = new TextWriterTraceListener("Errors.log");
            TextWriterTraceListener infoListner = new TextWriterTraceListener("Log.log");
            StreamWriter swErrors = errorListner.Writer as StreamWriter;
            if (swErrors != null) swErrors.AutoFlush = true;
            StreamWriter swInfo = infoListner.Writer as StreamWriter;
            if (swInfo != null) swInfo.AutoFlush = true;
            errorListner.Filter = new EventTypeFilter(SourceLevels.Error);

            infoListner.Filter = new EventTypeFilter(SourceLevels.Information);
            //  consoleListner.Filter = new EventTypeFilter(SourceLevels.All);
            clientTrace.Switch.Level = SourceLevels.All;
            clientTrace.Listeners.Add(errorListner);
            clientTrace.Listeners.Add(infoListner);

        }
        static public void DisposeProxy()
        {
            try
            {
                clientTrace.TraceEvent(TraceEventType.Information, _traceID++, 
                    "Closing proxy service");
                _client.Close();
                
                
            }
            catch (TimeoutException ex)
            {
                clientTrace.TraceEvent(TraceEventType.Error, _traceID++,
                    "Closing proxy service failed with TimeOutException \r\n\t" + ex.Message);
                _client.Abort();
            }
            catch (CommunicationException ex)
            {
                clientTrace.TraceEvent(TraceEventType.Error, _traceID++,
                    "Closing proxy service failed with CommunicationException \r\n\t" + ex.Message);
                _client.Abort();
            }
            catch (Exception ex)
            {
                clientTrace.TraceEvent(TraceEventType.Error, _traceID++,
                    "Closing proxy service failed with unrecognised Exception \r\n\t" + ex.Message);
                _client.Abort();
            }
        }

        static public void OpenProxy()
        {
            try
            {
             _client.Open();
                clientTrace.TraceEvent(TraceEventType.Information, _traceID++,
                    "Proxy service opened");
            }
            catch(TimeoutException ex)
            {
                clientTrace.TraceEvent(TraceEventType.Critical, _traceID++,
                    "Creating proxy service failed with TimeOutException exception \r\n\t" + ex.Message);
                throw ex;
                
            }
            catch (CommunicationException ex)
            {
                clientTrace.TraceEvent(TraceEventType.Critical, _traceID++,
                    "Creating proxy service failed with ComunicationException \r\n\t" + ex.Message);
                throw ex;
            }
            catch (Exception ex)
            {
                clientTrace.TraceEvent(TraceEventType.Critical, _traceID++,
                    "Creating proxy service failed with unrecognised Exception \r\n\t" + ex.Message);
                throw ex;
            }
        }



        static public T Call<T>(Func<ServiceReference1.ProcessingServiceClient, T> method)
        {
            
            try
            {
                T buf = method.Invoke(_client);
                _reconnectsLeft = _numberOfReconnection;
                return buf;
            }
            catch(Exception ex)
            {
                clientTrace.TraceEvent(TraceEventType.Error, _traceID++, "Call<T>(Func<T>) failed with Exception, {0} retries left \r\n\t" + ex.Message,_reconnectsLeft);
                if (_reconnectsLeft<= 0)
                {
                    _reconnectsLeft = _numberOfReconnection;
                    DisposeProxy();
                    clientTrace.TraceEvent(TraceEventType.Critical, _traceID++, "Call<T>(Func<T>) critical fail, proxy service closed \r\n\t");
                    throw ex;
                    
                }
                else
                {
                    _reconnectsLeft--;
                    return Call(method);
                }
                
            }
           
        }
        static public void Call(Action<ServiceReference1.ProcessingServiceClient> method)
        {
            try
            {
                
                method.Invoke(_client);
                _reconnectsLeft = _numberOfReconnection;
            }

            catch (Exception ex)
            {
                clientTrace.TraceEvent(TraceEventType.Error, _traceID++, "Call(Action<T>) failed with Exception, {0} retries left \r\n\t" + ex.Message, _reconnectsLeft);
                if (_reconnectsLeft <= 0)
                {
                    _reconnectsLeft = _numberOfReconnection;
                    DisposeProxy();
                    clientTrace.TraceEvent(TraceEventType.Critical, _traceID++, "Call(Action<T>) critical fail, proxy service closed \r\n\t");
                    throw ex;

                }
                else
                {
                    _reconnectsLeft--;
                    Call(method);
                }

            }
        }
    }
}
